package com.tinckay.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.RandomUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.tinckay.common.constant.AmqpConstant;
import com.tinckay.common.constant.RedisConstant;
import com.tinckay.entity.po.PumpInfo;
import com.tinckay.entity.po.PumpMonData;
import com.tinckay.mapper.PumpInfoMapper;
import com.tinckay.service.PumpInfoService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.support.CorrelationData;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * <p>
 * 泵车基本信息 服务实现类
 * </p>
 *
 * @author Jean
 * @since 2018-11-06
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class PumpInfoServiceImpl extends ServiceImpl<PumpInfoMapper, PumpInfo> implements PumpInfoService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    @CacheEvict(value = "pumpInfoCache", key = "#code")
    @Transactional(rollbackFor = Exception.class)
    public boolean removeById(Serializable code) {
        redisTemplate.opsForHash().delete(RedisConstant.PUMP_INFO_MAP, code);
        boolean result = super.remove(new QueryWrapper<PumpInfo>().eq("code", code));
        sendMsg();
        return result;
    }

    @Override
    @Cacheable(value = "pumpInfoCache", key = "#code", unless = "#result == null")
    public PumpInfo getById(Serializable code) {
        return baseMapper.selectOne(new QueryWrapper<PumpInfo>().eq("code", code));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @Cacheable(value = "pumpInfoCache", key = "#pumpInfo.code")
    public PumpInfo savePumpInfo(PumpInfo pumpInfo) {
        baseMapper.insert(pumpInfo);
        cacheAndSendMsg();
        return pumpInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    @CachePut(value = "pumpInfoCache", key = "#pumpInfo.code")
    public PumpInfo updatePumpInfo(PumpInfo pumpInfo) {
        baseMapper.updateById(pumpInfo);
        cacheAndSendMsg();
        return pumpInfo;
    }

    private void cacheAndSendMsg() {
        List<PumpInfo> cacheList = super.list(null);
        Map<String, com.tinckay.common.object.PumpInfo> cacheMap = buildPumpInfo(cacheList);
        redisTemplate.delete(RedisConstant.PUMP_INFO_MAP);
        redisTemplate.opsForHash().putAll(RedisConstant.PUMP_INFO_MAP, cacheMap);
        sendMsg();
    }

    private Map<String, com.tinckay.common.object.PumpInfo> buildPumpInfo(List<PumpInfo> cacheList) {
        Map<String, com.tinckay.common.object.PumpInfo> cacheMap = cacheList.parallelStream().map(pumpInfo -> {
            com.tinckay.common.object.PumpInfo result = new com.tinckay.common.object.PumpInfo();
            BeanUtil.copyProperties(pumpInfo, result);
            return result;
        }).collect(Collectors.toMap(com.tinckay.common.object.PumpInfo::getCode, Function.identity()));
        return cacheMap;
    }

    @Override
    public List<String> allPumpCode() {
        return baseMapper.allPumpCode();
    }

    private void sendMsg() {
        rabbitTemplate.convertAndSend(
                AmqpConstant.REDIS_CHANGE_FANOUT_EXCHANGE,
                null,
                RedisConstant.PUMP_INFO_MAP,
                new CorrelationData(RandomUtil.simpleUUID())
        );
    }

}
